home *** CD-ROM | disk | FTP | other *** search
/ SGI Hot Mix 17 / Hot Mix 17.iso / HM17_SGI / research / examples / demo / demosrc / d_volrendr.pro < prev    next >
Text File  |  1997-07-08  |  54KB  |  1,604 lines

  1. ; $Id: d_volrendr.pro,v 1.31 1997/04/25 22:46:18 tremblay Exp $
  2. ;
  3. ;  Copyright (c) 1997, Research Systems, Inc. All rights reserved.
  4. ;       Unauthorized reproduction prohibited.
  5. ;
  6. ;+
  7. ;  FILE:
  8. ;       d_volrendr.pro
  9. ;
  10. ;  CALLING SEQUENCE: d_volrendr
  11. ;
  12. ;  PURPOSE:
  13. ;       Shows the volume rendering techniques.
  14. ;
  15. ;  MAJOR TOPICS: Visualization and data processing.
  16. ;
  17. ;  CATEGORY:
  18. ;       IDL 5.0
  19. ;
  20. ;  INTERNAL FUNCTIONS and PROCEDURES:
  21. ;       pro add_Table           - Create a list of widget buttons
  22. ;       pro set_Table           - Set the opacity table list
  23. ;       fun load_Volume         - Read the volume data set
  24. ;       fun toggle_State        - Toggle the on/off name
  25. ;       pro volrendr_Event       - Event handler
  26. ;       pro volrendr_Cleanup     - Cleanup
  27. ;       pro d_volrendr             - Main procedure
  28. ;  EXTERNAL FUNCTIONS, PROCEDURES, and FILES:
  29. ;       pro trackball__define   - Create the trackball object
  30. ;       volrendr.txt
  31. ;       16cols.pal
  32. ;       banded.pal
  33. ;       bess.pal
  34. ;       gray.pal
  35. ;       solid.pal
  36. ;       voxel.pal
  37. ;       bess.opa
  38. ;       layer.opa
  39. ;       voxel.opa
  40. ;
  41. ;  REFERENCE: IDL Reference Guide, IDL User's Guide
  42. ;
  43. ;  NAMED STRUCTURES:
  44. ;       none.
  45. ;
  46. ;  COMMON BLOCS:
  47. ;       none.
  48. ;
  49. ;  MODIFICATION HISTORY: Written by RF, RSI, 1996
  50. ;                        Modified by DAT,RSI,   1996 New GUI
  51. ;
  52. ;-
  53.  
  54. ;----------------------------------------------------------------------------
  55. ;
  56. ;    PURPOSE  Add a table list to the options (buttons)
  57. ;
  58. pro Add_Tables, $
  59.     wild, $     ; IN: wild card character ex: *.opa
  60.     wid, $      ; IN: Parent widget id. New button will be childs.
  61.     uval, $     ; IN: user value assigned to the created buttons. 
  62.     list, $     ; OUT: list all the file found
  63.     widgetList  ; OUT: created widget button IDs 
  64.  
  65.     ;  Go to the current directory.
  66.     ;
  67.     cd, cur=cur
  68.    
  69.     ;  Go to the directory that has all the table files.
  70.     ;
  71.     cd, filepath('', SUBDIR=['examples','demo','demodata'])
  72.  
  73.     ;  Find all the file that ends by the characters spuecified
  74.     ;  by  'wild' .
  75.     ;
  76.     list=findfile(wild)
  77.     szlist = size(list)
  78.  
  79.     ;  filepath under VMS always returns full path
  80.     ;  this must be removed
  81.     ;
  82.     if (!VERSION.OS_FAMILY EQ 'vms') then begin
  83.         for i=0, n_elements(list)-1 do begin
  84.            bracketPos = RSTRPOS(list[i],']')
  85.            if (bracketPos GE 0) then begin
  86.               list[i]=strmid(list[i], bracketPos+1, $
  87.                  STRLEN(list[i])-bracketPos-1)
  88.            endif
  89.            semicolonPos = STRPOS(list[i],';')
  90.            if (semicolonPos GE 0) then begin
  91.              list[i]=strmid(list[i], 0, semicolonPos)
  92.            endif
  93.         endfor
  94.     endif
  95.  
  96.     ;  Create a widget button for each file. Make the widget button
  97.     ;  to be the child of 'wid', and the uservalue is 'uval'.
  98.     ;
  99.     widgetList = LONARR(szlist(1))
  100.  
  101.     for i=0,n_elements(list)-1 do begin
  102.         widgetList(i)=WIDGET_BUTTON(wid, VALUE=list(i), UVALUE=uval)
  103.     end
  104.  
  105.     ;  Return to previous directory.
  106.     ;
  107.     cd, cur
  108. end
  109.  
  110. ;----------------------------------------------------------------------------
  111. ;
  112. ;    PURPOSE  Set the color or opacity table.
  113. ;
  114. pro Set_Table, $
  115.     oVolume, $       ; IN: volume object
  116.     widgetID, $           ; IN: button widget ID
  117.     which            ; IN: table type. 0=color, 1= opacity
  118.  
  119.     ;  Get the button value which is the filename.
  120.     ;
  121.     WIDGET_CONTROL, widgetID, GET_VALUE=filename
  122.  
  123.     ;  Read the table(color or opacity).
  124.     ;
  125.     GET_LUN, lun
  126.     newTable = BYTARR(256,3)
  127.  
  128.     OPENR, lun, filepath(filename, $
  129.         SUBDIR=['examples','demo','demodata'])
  130.     READU, lun, newTable
  131.     CLOSE, lun
  132.     FREE_LUN,lun
  133.  
  134.     ;  Branch to the case of color (0) or opacity table(1).
  135.     ;  Then set the object property to that table.
  136.     ;
  137.     case which of
  138.  
  139.         ;  Set the RGB color table.
  140.         ;
  141.         0 : begin
  142.             oVolume->SetProperty, RGB_TABLE0=newTable
  143.         end   ;  of 0
  144.  
  145.         ;  Set the opacity table.
  146.         ;
  147.         1 : begin
  148.             oVolume->SetProperty, OPACITY_TABLE0=newTable(*,0)
  149.         end   ;  of 1
  150.  
  151.     endcase
  152.  
  153. end       ;    of Set_Table
  154.  
  155. ;----------------------------------------------------------------------------
  156. ;
  157. ;    PURPOSE  Set the the color or opacity table.
  158. ;
  159. function load_volume, $
  160.     which, $          ; String identifying which volume to load.
  161.     parentModel       ; Parent model of the newly created volume object.
  162.  
  163.     ;  Get a lun.
  164.     ;
  165.     GET_LUN,lun
  166.  
  167.     ;  Branch to the appropriate volume.
  168.     ;
  169.     case which of
  170.  
  171.         ;  Load the heart volume.
  172.         ;
  173.         'Heart': begin
  174.             data = BYTARR(202,132,144)
  175.             OPENR, lun, filepath('heart.bin', $
  176.                 SUBDIR=['examples','demo','demodata'])
  177.             READU, lun,data
  178.             CLOSE, lun
  179.  
  180.             ;  Make the solid palette color table the default.
  181.             ;
  182.             colors = BYTARR(256,3, /NOZERO)
  183.             OPENR, lun, filepath('solid.pal', $
  184.                 SUBDIR=['examples','demo','demodata'])
  185.             READU, lun, colors
  186.             CLOSE,lun
  187.  
  188.             ;  Make the solid opacity table the default.
  189.             ;
  190.             opac = BYTARR(256, /NOZERO)
  191.             OPENR, lun, filepath('solid.opa', $
  192.                 SUBDIR=['examples','demo','demodata'])
  193.             READU, lun, opac
  194.             CLOSE, lun
  195.             zc = 1.0
  196.         end    ;  of Heart
  197.  
  198.         ;  Load the brain volume.
  199.         ;
  200.         'Brain': begin
  201.  
  202.             ;  Read the brain data.
  203.             ;
  204.             data = BYTARR(148,156,108, /NOZERO)
  205.             if 0 then begin     ;Old way
  206.                 OPENR, lun, filepath('brain.bin', $
  207.                                      SUBDIR=['examples','demo','demodata'])
  208.                 READU, lun, data
  209.             ENDIF ELSE BEGIN    ;Read compressed data
  210.                 OPENR, lun, filepath('brain.gif', $
  211.                                      SUBDIR=['examples','demo','demodata'])
  212.                 DECODE_GIF, Lun, Data
  213.             ENDELSE
  214.             CLOSE, lun
  215.             
  216.             ;  Make the voxel palette color table the default.
  217.             ;
  218.             colors = BYTARR(256,3, /NOZERO)
  219.             OPENR, lun, filepath('voxel.pal', $
  220.                 SUBDIR=['examples','demo','demodata'])
  221.             READU, lun, colors
  222.             CLOSE, lun
  223.  
  224.             ;  Make the voxel opacity table the default.
  225.             ;
  226.             opac = BYTARR(256, /NOZERO)
  227.             OPENR,lun, filepath('voxel.opa', $
  228.                 SUBDIR=['examples','demo','demodata'])
  229.             READU, lun, opac
  230.             CLOSE, lun
  231.             zc = 1.5/0.9375
  232.         end     ;    of Brain
  233.  
  234.         ;  Load the Bessel volume.
  235.         ;
  236.         'Bessel': begin
  237.  
  238.             ;  Create the bessel data, the opacity and the color
  239.             ;  tables. 
  240.             ;
  241.             z = FLTARR(40,40,20, /NOZERO)
  242.             x = SHIFT(DIST(40), 20, 20)
  243.  
  244.             for i = 0, 19 do z(*,*,i)=BESELJ(x/2, i)
  245.             data=BYTARR(40,40,20)
  246.             data=BYTE(((z+0.4)/1.4)*255)
  247.             opac = BYTARR(256)
  248.             opac = BINDGEN(256)/4
  249.             colors = BYTARR(256,3)
  250.             colors(*,*) =0
  251.             colors(*,1) = BINDGEN(256)
  252.             zc = 1.0
  253.         end    ;  of Bessel
  254.  
  255.     endcase     ;  of    which
  256.  
  257.     ;  Create the volume object.
  258.     ;
  259.     FREE_LUN,lun
  260.  
  261.     ;  Set up XYZcoord_conv to center and scale the volume.
  262.     ;
  263.     i = SIZE(data)
  264.     m = FLOAT(max(i[1:3]))
  265.     sx = 1.0/m
  266.     sy = 1.0/m
  267.     sz = (1.0/m)*zc
  268.     ox = -(float(i[1])*sx)*0.5
  269.     oy = -(float(i[2])*sy)*0.5
  270.     oz = -(float(i[3])*sz)*0.5
  271.  
  272.     oVolume = OBJ_NEW('IDLgrVolume',data, $
  273.         xcoord_conv=[ox, sx], $
  274.         ycoord_conv=[oy, sy], $
  275.         zcoord_conv=[oz, sz] $
  276.     )
  277.  
  278.     oVolume->SetProperty, opacity_table0=opac, $
  279.         /ZERO_OPACITY_SKIP, $
  280.         RGB_TABLE0=colors,HIDE=1
  281.  
  282.     oVolume->SetProperty, /ZBUFFER
  283.  
  284.     parentModel->Add, oVolume
  285.  
  286.     if (which EQ 'Heart') then begin
  287.         oVolume->SetProperty, AMBIENT=[130,130,130]
  288.     endif
  289.  
  290.     ;  Return the volume object.
  291.     ;
  292.     RETURN, oVolume
  293.  
  294. end         ;  load_volume
  295.  
  296. ;----------------------------------------------------------------------------
  297. ;
  298. ;    PURPOSE  Toggle the buton state between off and on.
  299. ;
  300. function Toggle_state, $
  301.     widgetID         ; IN: button widget identifer.
  302.  
  303.     WIDGET_CONTROL, widgetID, GET_VALUE=name
  304.  
  305.     s = STRPOS(name,'(off)')
  306.     if (s NE -1) then begin
  307.         STRPUT, name, '(on )', s
  308.         ret = 1
  309.     endif else begin
  310.         s = STRPOS(name,'(on )')
  311.         STRPUT, name, '(off)', s
  312.         ret = 0
  313.     endelse
  314.  
  315.     WIDGET_CONTROL, widgetID, SET_VALUE=name
  316.     RETURN, ret
  317. end
  318.  
  319. ;----------------------------------------------------------------------------
  320. ;
  321. ;    PURPOSE  Toggle the buton state between off and on.
  322. ;
  323. pro volrendr_event, $
  324.     sEvent             ; IN: event structure.
  325.  
  326.     if (TAG_NAMES(sEvent, /STRUCTURE_NAME) EQ  $
  327.         'WIDGET_KILL_REQUEST') then begin
  328.         WIDGET_CONTROL, sEvent.top, /DESTROY
  329.         RETURN
  330.     endif
  331.  
  332.     ;  Get the event user value.
  333.     ;
  334.     WIDGET_CONTROL, sEvent.id, GET_UVALUE=uval
  335.  
  336.     ;  Branch to the correct event user value.
  337.     ;
  338.     case uval of
  339.  
  340.         ;  CHange the color table.
  341.         ;
  342.         'COLOR_TAB' : begin
  343.             WIDGET_CONTROL, sEvent.top, GET_UVALUE=state, /NO_COPY
  344.             Set_Table, state.oVolumeArray(state.cur), sEvent.id, 0
  345.  
  346.             if (state.autoR EQ 0 ) then begin
  347.                 state.oWindow->SetProperty, QUALITY=0
  348.             endif else begin
  349.                 state.oWindow->SetProperty, QUALITY=2
  350.             endelse
  351.  
  352.             WIDGET_CONTROL, state.wBase, SENSITIVE=0
  353.             state.oWindow->Draw, state.oView    
  354.             WIDGET_CONTROL, state.wBase, SENSITIVE=1
  355.             state.isDrawn = 0
  356.  
  357.             ;  Set isDrawn to 0 to avoid redrawing again (no expose event).
  358.             ;
  359.             state.isDrawn = 0
  360.  
  361.             WIDGET_CONTROL, sEvent.id, GET_VALUE=evvalue, /NO_COPY
  362.             sizewidget = size(state.colorWidgetID)
  363.  
  364.             for i = 0, sizeWidget(1)-1 do begin
  365.                 WIDGET_CONTROL, state.colorWidgetID(i), GET_VALUE=widgetValue
  366.                 WIDGET_CONTROL, state.colorWidgetID(i), SENSITIVE=1
  367.                 if (widgetValue EQ evvalue) then begin
  368.                      WIDGET_CONTROL, state.colorWidgetID(i), SENSITIVE=0
  369.                 endif
  370.             endfor
  371.             WIDGET_CONTROL, sEvent.top, SET_UVALUE=state, /NO_COPY
  372.         end  ; of COLOR_TAB
  373.  
  374.         ;  Change to a new opacity table.
  375.         ;
  376.         'OPACITY_TAB' : begin
  377.             WIDGET_CONTROL, sEvent.top, GET_UVALUE=state, /NO_COPY
  378.             Set_Table, state.oVolumeArray(state.cur), sEvent.id, 1
  379.  
  380.             if (state.autoR EQ 0 ) then begin
  381.                 state.oWindow->SetProperty, QUALITY=0
  382.             endif else begin
  383.                 state.oWindow->SetProperty, QUALITY=2
  384.             endelse
  385.  
  386.             WIDGET_CONTROL, state.wBase, SENSITIVE=0
  387.             state.oWindow->Draw, state.oView    
  388.             WIDGET_CONTROL, state.wBase, SENSITIVE=1
  389.  
  390.             ;  Opcaity table does not create an expose event.....
  391.             ;  Therefore set isDrawn to 0.
  392.             ;
  393.             state.isDrawn = 0
  394.             WIDGET_CONTROL, sEvent.id, GET_VALUE=evvalue, /NO_COPY
  395.             sizewidget = SIZE(state.opacityWidgetID)
  396.  
  397.             for i = 0, sizeWidget(1)-1 do begin
  398.                 WIDGET_CONTROL, state.opacityWidgetID(i), GET_VALUE= widgetValue
  399.                 WIDGET_CONTROL, state.opacityWidgetID(i), SENSITIVE=1
  400.                 if (widgetValue EQ evvalue) then begin
  401.                     WIDGET_CONTROL, state.opacityWidgetID(i), SENSITIVE=0
  402.                 endif
  403.             endfor
  404.  
  405.             WIDGET_CONTROL, sEvent.top, SET_UVALUE=state, /NO_COPY
  406.         end   ; of OPACITY_TAB
  407.  
  408.         ;  Render the image and display it.
  409.         ;
  410.         'RENDER' : begin
  411.             WIDGET_CONTROL, sEvent.top, GET_UVALUE=state, /NO_COPY
  412.             WIDGET_CONTROL,sEvent.top, /HOURGLASS    
  413.             state.oWindow->SetProperty, QUALITY=2
  414.             WIDGET_CONTROL, state.wBase, SENSITIVE=0
  415.             state.oWindow->Draw,state.oView    
  416.             state.isDrawn = 1
  417.             WIDGET_CONTROL, state.wBase, SENSITIVE=1
  418.             WIDGET_CONTROL, sEvent.top, SET_UVALUE=state, /NO_COPY
  419.         end   ; of RENDER
  420.  
  421.         ;  Compute the MIP rendering technique and display the result.
  422.         ;
  423.         'SMIP': begin
  424.             WIDGET_CONTROL, sEvent.top, GET_UVALUE=state, /NO_COPY
  425.             j = Toggle_State(sEvent.id)
  426.  
  427.             for i = 0, N_ELEMENTS(state.oVolumeArray)-1 do begin
  428.                 state.oVolumeArray(i)->SetProperty, COMPOSITE_FUNCTION=j
  429.             endfor
  430.  
  431.             if (state.autoR EQ 0 ) then begin
  432.                 state.oWindow->SetProperty, QUALITY=0
  433.             endif else begin
  434.                 state.oWindow->SetProperty, QUALITY=2
  435.             endelse
  436.  
  437.             WIDGET_CONTROL, state.wBase, SENSITIVE=0
  438.             state.oWindow->Draw, state.oView    
  439.             WIDGET_CONTROL, state.wBase, SENSITIVE=1
  440.             state.isDrawn = 1
  441.             WIDGET_CONTROL, sEvent.top, SET_UVALUE=state, /NO_COPY
  442.         end   ; of SMIP
  443.  
  444.         ;  Handle the Left Mouse Button SCALE of the volume.
  445.         ;
  446.         'LMBSCALE': begin
  447.             WIDGET_CONTROL, sEvent.top, GET_UVALUE=state, /NO_COPY
  448.             state.LMBscale = Toggle_State(sEvent.id)
  449.  
  450.             if (state.autoR EQ 0 ) then begin
  451.                 state.oWindow->SetProperty, QUALITY=0
  452.             endif else begin
  453.                 state.oWindow->SetProperty, QUALITY=2
  454.             endelse
  455.  
  456.             WIDGET_CONTROL, state.wBase, SENSITIVE=0
  457.             state.oWindow->Draw, state.oView    
  458.             WIDGET_CONTROL, state.wBase, SENSITIVE=1
  459.             state.isDrawn = 1
  460.             WIDGET_CONTROL, sEvent.top, SET_UVALUE=state, /NO_COPY
  461.         end   ; of LMBSCALE
  462.  
  463.         ;  Set on or off the auto rendering property.
  464.         ;
  465.         'AUTORENDER' : begin
  466.             WIDGET_CONTROL, sEvent.top, GET_UVALUE=state, /NO_COPY
  467.             state.autoR = Toggle_State(sEvent.id)
  468.  
  469.             if (state.autoR EQ 0 ) then begin
  470.                 state.oWindow->SetProperty, QUALITY=0
  471.              endif else begin
  472.                 state.oWindow->SetProperty, QUALITY=2
  473.              endelse
  474.  
  475.              WIDGET_CONTROL, state.wBase, SENSITIVE=0
  476.              state.oWindow->Draw, state.oView    
  477.              WIDGET_CONTROL, state.wBase, SENSITIVE=1
  478.              state.isDrawn = 1
  479.              WIDGET_CONTROL, sEvent.top, SET_UVALUE=state, /NO_COPY
  480.         end   ; of AUTORENDER
  481.  
  482.         ;  Select a volume to display.
  483.         ;
  484.         'VOLSEL': begin
  485.             WIDGET_CONTROL, sEvent.top, GET_UVALUE=state, /NO_COPY
  486.  
  487.             ;  Hide the annnotation text (all 3).
  488.             ;
  489.             for i=3,5 do state.oOtherObjectArray(i)->SetProperty, HIDE=1
  490.  
  491.             state.oVolumeArray(state.cur)->GetProperty, RGB_TABLE0=curColorTable
  492.             state.oVolumeArray(state.cur)->GetProperty, $
  493.                 OPACITY_TABLE0=curOpacityTable
  494.  
  495.             case sEvent.value of
  496.  
  497.                 ;  Show the brain.
  498.                 ;
  499.                 0: begin
  500.                     state.oVolumeArray(0)->SetProperty, HIDE=0
  501.                     state.oVolumeArray(1)->SetProperty, HIDE=1
  502.                     state.oOtherObjectArray(4)->SetProperty, HIDE=0
  503.             end
  504.  
  505.                 ;  Show the bessel function.
  506.                 ;
  507.                 1: begin
  508.                     state.oVolumeArray(0)->SetProperty, HIDE=1
  509.                     state.oVolumeArray(1)->SetProperty, HIDE=0
  510.                     state.oOtherObjectArray(5)->SetProperty, HIDE=0
  511.                 end
  512.  
  513.             endcase
  514.  
  515.             state.cur = sEvent.value 
  516.  
  517.             for i = 0, N_ELEMENTS(state.oVolumeArray)-1 do begin
  518.                 state.oVolumeArray(i)->SetProperty, $
  519.                     RGB_TABLE0=curColorTable
  520.                 state.oVolumeArray(i)->SetProperty, $
  521.                     OPACITY_TABLE0=curOpacityTable
  522.             endfor
  523.  
  524.             ;  Redraw the volume.
  525.             ;
  526.             WIDGET_CONTROL, state.wBase, SENSITIVE=0
  527.  
  528.             state.oWindow->Draw, state.oView    
  529.             WIDGET_CONTROL, state.wBase, SENSITIVE=1
  530.  
  531.             state.isDrawn = 1
  532.             WIDGET_CONTROL, sEvent.top, SET_UVALUE=state, /NO_COPY
  533.         end   ; of VOLSEL
  534.  
  535.         ;  Turn on or off the lights.
  536.         ;
  537.         'LIGHTING': begin
  538.             WIDGET_CONTROL, sEvent.top, GET_UVALUE=state, /NO_COPY
  539.             j = Toggle_State(sEvent.id)
  540.  
  541.             for i = 0, N_ELEMENTS(state.oVolumeArray)-1 do begin
  542.                 state.oVolumeArray(i)->SetProperty, LIGHTING_MODEL=j
  543.             endfor
  544.             if (state.autoR EQ 0 ) then begin
  545.                 state.oWindow->SetProperty, QUALITY=0
  546.             endif else begin
  547.                 state.oWindow->SetProperty, QUALITY=2
  548.             endelse
  549.  
  550.             ;  Redraw the volume.
  551.             ;
  552.             WIDGET_CONTROL, state.wBase, SENSITIVE=0
  553.             state.oWindow->Draw, state.oView    
  554.             WIDGET_CONTROL, state.wBase, SENSITIVE=1
  555.  
  556.             state.isDrawn = 1
  557.             WIDGET_CONTROL, sEvent.top, SET_UVALUE=state, /NO_COPY
  558.         end   ; of LIGHTING
  559.  
  560.         ;  Add (or remove) the wire box object.
  561.         ;
  562.         'WIREBOX' : begin
  563.             WIDGET_CONTROL, sEvent.top, GET_UVALUE=state, /NO_COPY
  564.             j = Toggle_State(sEvent.id)
  565.  
  566.             ;  oOtherObjectArray(0)  is the wire box object.
  567.             ;  Hide or show it.
  568.             ;
  569.             state.oOtherObjectArray(0)->SetProperty, HIDE=1-j
  570.  
  571.             if (state.autoR EQ 0 ) then begin
  572.                 state.oWindow->SetProperty, QUALITY=0
  573.             endif else begin
  574.                 state.oWindow->SetProperty, QUALITY=2
  575.             endelse
  576.  
  577.             WIDGET_CONTROL, state.wBase, SENSITIVE=0
  578.             state.oWindow->Draw, state.oView    
  579.             WIDGET_CONTROL, state.wBase, SENSITIVE=1
  580.             state.isDrawn = 1
  581.             WIDGET_CONTROL, sEvent.top, SET_UVALUE=state, /NO_COPY
  582.         end   ; of WIREBOX
  583.  
  584.         ;  Add or remove the solid plane object.
  585.         ;
  586.         'SOLIDPLANE' : begin
  587.             WIDGET_CONTROL, sEvent.top, GET_UVALUE=state, /NO_COPY
  588.             j = Toggle_State(sEvent.id)
  589.  
  590.             ;  oOtherObjectArray(1)  is the solid plane object.
  591.             ;  Hide or show it.
  592.             ;
  593.             state.oOtherObjectArray(1)->SetProperty, HIDE=1-j
  594.             if (state.autoR EQ 0 ) then begin
  595.                 state.oWindow->SetProperty, QUALITY=0
  596.             endif else begin
  597.                 state.oWindow->SetProperty, QUALITY=2
  598.             endelse
  599.  
  600.             WIDGET_CONTROL, state.wBase, SENSITIVE=0
  601.             state.oWindow->Draw, state.oView    
  602.             WIDGET_CONTROL, state.wBase, SENSITIVE=1
  603.  
  604.             state.isDrawn = 1
  605.             WIDGET_CONTROL, sEvent.top, SET_UVALUE=state, /NO_COPY
  606.         end   ; of SOLIDPLANE
  607.  
  608.         ;  Add or remove the (3 axes) object.
  609.         ;
  610.         'AXES' : begin
  611.             WIDGET_CONTROL, sEvent.top, GET_UVALUE=state, /NO_COPY
  612.             j = Toggle_State(sEvent.id)
  613.  
  614.             ;  oOtherObjectArray(2)  is the axes object.
  615.             ;  Hide or show it.
  616.             ;
  617.             state.oOtherObjectArray(2)->SetProperty,HIDE=1-j
  618.             if (state.autoR EQ 0 ) then begin
  619.                 state.oWindow->SetProperty, QUALITY=0
  620.             endif else begin
  621.                 state.oWindow->SetProperty, QUALITY=2
  622.             endelse
  623.  
  624.            WIDGET_CONTROL, state.wBase, SENSITIVE=0
  625.             state.oWindow->Draw, state.oView    
  626.             WIDGET_CONTROL, state.wBase, SENSITIVE=1
  627.  
  628.             state.isDrawn = 1
  629.             WIDGET_CONTROL, sEvent.top, SET_UVALUE=state, /NO_COPY
  630.         end   ; of AXES
  631.  
  632.         ;  Set the render step to 111.
  633.         ;
  634.         'RENDERSTEP111' : begin
  635.             WIDGET_CONTROL, sEvent.top, GET_UVALUE=state, /NO_COPY
  636.             step = [1,1,1]
  637.             for i = 0, N_ELEMENTS(state.oVolumeArray)-1 do begin
  638.                 state.oVolumeArray(i)->SetProperty, RENDER_STEP=step
  639.             endfor
  640.             WIDGET_CONTROL, state.wRenderStep111Button, SENSITIVE=0
  641.             WIDGET_CONTROL, state.wRenderStep112Button, SENSITIVE=1
  642.             WIDGET_CONTROL, state.wRenderStep114Button, SENSITIVE=1
  643.             WIDGET_CONTROL, state.wRenderStep221Button, SENSITIVE=1
  644.             WIDGET_CONTROL, state.wRenderStep222Button, SENSITIVE=1
  645.             WIDGET_CONTROL, state.wRenderStep444Button, SENSITIVE=1
  646.  
  647.             if (state.autoR EQ 0 ) then begin
  648.                 state.oWindow->SetProperty, QUALITY=0
  649.             endif else begin
  650.                 state.oWindow->SetProperty, QUALITY=2
  651.             endelse
  652.  
  653.             WIDGET_CONTROL, state.wBase, SENSITIVE=0
  654.             state.oWindow->Draw, state.oView    
  655.             WIDGET_CONTROL, state.wBase, SENSITIVE=1
  656.             state.isDrawn = 1
  657.             state.renderStepFlag = 1
  658.             WIDGET_CONTROL, sEvent.top, SET_UVALUE=state, /NO_COPY
  659.         end ; of RENDERSTEP111
  660.  
  661.         ;  Set the render step to 112.
  662.         ;
  663.         'RENDERSTEP112' : begin
  664.             WIDGET_CONTROL, sEvent.top, GET_UVALUE=state, /NO_COPY
  665.             step = [1,1,2]
  666.             for i = 0, N_ELEMENTS(state.oVolumeArray)-1 do begin
  667.                 state.oVolumeArray(i)->SetProperty, RENDER_STEP=step
  668.             endfor
  669.             WIDGET_CONTROL, state.wRenderStep111Button, SENSITIVE=1
  670.             WIDGET_CONTROL, state.wRenderStep112Button, SENSITIVE=0
  671.             WIDGET_CONTROL, state.wRenderStep114Button, SENSITIVE=1
  672.             WIDGET_CONTROL, state.wRenderStep221Button, SENSITIVE=1
  673.             WIDGET_CONTROL, state.wRenderStep222Button, SENSITIVE=1
  674.             WIDGET_CONTROL, state.wRenderStep444Button, SENSITIVE=1
  675.  
  676.             if (state.autoR EQ 0 ) then begin
  677.                 state.oWindow->SetProperty, QUALITY=0
  678.             endif else begin
  679.                 state.oWindow->SetProperty, QUALITY=2
  680.             endelse
  681.  
  682.             WIDGET_CONTROL, state.wBase, SENSITIVE=0
  683.             state.oWindow->Draw, state.oView    
  684.             WIDGET_CONTROL, state.wBase, SENSITIVE=1
  685.  
  686.             state.isDrawn = 1
  687.             state.renderStepFlag = 1
  688.             WIDGET_CONTROL, sEvent.top, SET_UVALUE=state, /NO_COPY
  689.         end ; of RENDERSTEP112
  690.  
  691.         ;  Set the render step to 114.
  692.         ;
  693.         'RENDERSTEP114' : begin
  694.             WIDGET_CONTROL, sEvent.top, GET_UVALUE=state, /NO_COPY
  695.             step = [1,1,4]
  696.             for i = 0, N_ELEMENTS(state.oVolumeArray)-1 do begin
  697.                 state.oVolumeArray(i)->SetProperty, RENDER_STEP=step
  698.             endfor
  699.             WIDGET_CONTROL, state.wRenderStep111Button, SENSITIVE=1
  700.             WIDGET_CONTROL, state.wRenderStep112Button, SENSITIVE=1
  701.             WIDGET_CONTROL, state.wRenderStep114Button, SENSITIVE=0
  702.             WIDGET_CONTROL, state.wRenderStep221Button, SENSITIVE=1
  703.             WIDGET_CONTROL, state.wRenderStep222Button, SENSITIVE=1
  704.             WIDGET_CONTROL, state.wRenderStep444Button, SENSITIVE=1
  705.  
  706.             if (state.autoR EQ 0 ) then begin
  707.                 state.oWindow->SetProperty, QUALITY=0
  708.             endif else begin
  709.                 state.oWindow->SetProperty, QUALITY=2
  710.             endelse
  711.  
  712.             WIDGET_CONTROL, state.wBase, SENSITIVE=0
  713.             state.oWindow->Draw, state.oView    
  714.             WIDGET_CONTROL, state.wBase, SENSITIVE=1
  715.             state.isDrawn = 1
  716.             state.renderStepFlag = 1
  717.             WIDGET_CONTROL, sEvent.top, SET_UVALUE=state, /NO_COPY
  718.         end ; of RENDERSTEP114
  719.  
  720.         ;  Set the render step to 221.
  721.         ;
  722.         'RENDERSTEP221' : begin
  723.             WIDGET_CONTROL, sEvent.top, GET_UVALUE=state, /NO_COPY
  724.             step = [2,2,1]
  725.             for i = 0, N_ELEMENTS(state.oVolumeArray)-1 do begin
  726.                 state.oVolumeArray(i)->SetProperty, RENDER_STEP=step
  727.             endfor
  728.             WIDGET_CONTROL, state.wRenderStep111Button, SENSITIVE=1
  729.             WIDGET_CONTROL, state.wRenderStep112Button, SENSITIVE=1
  730.             WIDGET_CONTROL, state.wRenderStep114Button, SENSITIVE=1
  731.             WIDGET_CONTROL, state.wRenderStep221Button, SENSITIVE=0
  732.             WIDGET_CONTROL, state.wRenderStep222Button, SENSITIVE=1
  733.             WIDGET_CONTROL, state.wRenderStep444Button, SENSITIVE=1
  734.             if (state.autoR EQ 0 ) then begin
  735.                 state.oWindow->SetProperty, QUALITY=0
  736.             endif else begin
  737.                 state.oWindow->SetProperty, QUALITY=2
  738.             endelse
  739.             WIDGET_CONTROL, state.wBase, SENSITIVE=0
  740.             state.oWindow->Draw, state.oView    
  741.             WIDGET_CONTROL, state.wBase, SENSITIVE=1
  742.             state.isDrawn = 1
  743.             state.renderStepFlag = 1
  744.             WIDGET_CONTROL, sEvent.top, SET_UVALUE=state, /NO_COPY
  745.         end ; of RENDERSTEP221
  746.  
  747.         ;  Set the render step to 222.
  748.         ;
  749.         'RENDERSTEP222' : begin
  750.             WIDGET_CONTROL, sEvent.top, GET_UVALUE=state, /NO_COPY
  751.             step = [2,2,2]
  752.             for i = 0, N_ELEMENTS(state.oVolumeArray)-1 do begin
  753.                 state.oVolumeArray(i)->SetProperty, RENDER_STEP=step
  754.             endfor
  755.             WIDGET_CONTROL, state.wRenderStep111Button, SENSITIVE=1
  756.             WIDGET_CONTROL, state.wRenderStep112Button, SENSITIVE=1
  757.             WIDGET_CONTROL, state.wRenderStep114Button, SENSITIVE=1
  758.             WIDGET_CONTROL, state.wRenderStep221Button, SENSITIVE=1
  759.             WIDGET_CONTROL, state.wRenderStep222Button, SENSITIVE=0
  760.             WIDGET_CONTROL, state.wRenderStep444Button, SENSITIVE=1
  761.             if (state.autoR EQ 0 ) then begin
  762.                 state.oWindow->SetProperty, QUALITY=0
  763.             endif else begin
  764.                  state.oWindow->SetProperty, QUALITY=2
  765.             endelse
  766.             WIDGET_CONTROL, state.wBase, SENSITIVE=0
  767.             state.oWindow->Draw, state.oView    
  768.             WIDGET_CONTROL, state.wBase, SENSITIVE=1
  769.             state.isDrawn = 1
  770.             state.renderStepFlag = 1
  771.             WIDGET_CONTROL, sEvent.top, SET_UVALUE=state, /NO_COPY
  772.         end ; of RENDERSTEP222
  773.  
  774.         ;  Set the render step to 222.
  775.         ;
  776.         'RENDERSTEP444' : begin
  777.             WIDGET_CONTROL, sEvent.top, GET_UVALUE=state, /NO_COPY
  778.             step = [4,4,4]
  779.             for i = 0, N_ELEMENTS(state.oVolumeArray)-1 do begin
  780.                 state.oVolumeArray(i)->SetProperty, RENDER_STEP=step
  781.             endfor
  782.             WIDGET_CONTROL, state.wRenderStep111Button, SENSITIVE=1
  783.             WIDGET_CONTROL, state.wRenderStep112Button, SENSITIVE=1
  784.             WIDGET_CONTROL, state.wRenderStep114Button, SENSITIVE=1
  785.             WIDGET_CONTROL, state.wRenderStep221Button, SENSITIVE=1
  786.             WIDGET_CONTROL, state.wRenderStep222Button, SENSITIVE=1
  787.             WIDGET_CONTROL, state.wRenderStep444Button, SENSITIVE=0
  788.  
  789.             if (state.autoR EQ 0 ) then begin
  790.                 state.oWindow->SetProperty, QUALITY=0
  791.             endif else begin
  792.                 state.oWindow->SetProperty, QUALITY=2
  793.             endelse
  794.  
  795.             WIDGET_CONTROL, state.wBase, SENSITIVE=0
  796.             state.oWindow->Draw, state.oView    
  797.             WIDGET_CONTROL, state.wBase, SENSITIVE=1
  798.             state.isDrawn = 1
  799.             state.renderStepFlag = 1
  800.             WIDGET_CONTROL, sEvent.top, SET_UVALUE=state, /NO_COPY
  801.         end ; of RENDERSTEP444
  802.  
  803.         ;  Perform the depth queuing.
  804.         ;  This portion of the code is commented out 
  805.         ;  because this option is not offered but it
  806.         ;  is provided for the user benefit.
  807.         ;
  808. ;          'DEPTHQ': begin
  809. ;              WIDGET_CONTROL, sEvent.top, GET_UVALUE=state, /NO_COPY
  810. ;              j = Toggle_State(sEvent.id)
  811. ;              case j of
  812. ;
  813. ;                  1 : begin
  814. ;                      for i=0,2 do begin
  815. ;                          state.oVolumeArray(i)->SetProperty,Depth_Queue=[-0.4,0.8]
  816. ;                      endfor
  817. ;                  end
  818. ;
  819. ;                  0 : begin
  820. ;                      for i=0,2 do begin
  821. ;                          state.oVolumeArray(i)->SetProperty,Depth_Queue=[0,0]
  822. ;                     endfor
  823. ;                  end
  824. ;              endcase
  825. ;
  826. ;              state.oWindow->Draw, state.oView    
  827. ;              WIDGET_CONTROL, sEvent.top, SET_UVALUE=state, /NO_COPY
  828. ;          end   ;  of DEPTHQ
  829. ;
  830.  
  831.         ;  Handle the event that occur in the drawing area.
  832.         ;
  833.         'DRAW': begin
  834.             WIDGET_CONTROL, sEvent.top, GET_UVALUE=state, /NO_COPY
  835.  
  836.             ;  Expose.
  837.             ;
  838.             if (sEvent.type eq 4) then begin
  839.                 if (state.initial EQ 1) then begin
  840.                     if (state.isDrawn EQ 0) then begin
  841.  
  842.                        if (state.renderStepFlag EQ 1) then begin
  843.                             state.renderStepFlag  = 0
  844.                             WIDGET_CONTROL, sEvent.top, SET_UVALUE=state, /NO_COPY
  845.                             RETURN
  846.                         endif
  847.  
  848.                         if (state.autoR EQ 1) then begin
  849.                             state.oWindow->SetProperty, QUALITY=2
  850.                         endif else begin
  851.                             state.oWindow->SetProperty, QUALITY=0
  852.                         endelse
  853.  
  854.                         WIDGET_CONTROL, state.wBase, SENSITIVE=0
  855.                         state.oWindow->draw, state.oView
  856.                         WIDGET_CONTROL, state.wBase, SENSITIVE=1
  857.                     endif   ;  of isDrawn = 0
  858.                 endif  ; of initial = 1
  859.                 state.initial = 1
  860.             endif  ; of event type = 4
  861.  
  862.             ;  Set the isDrawn flag to 0 ( object not drawn)
  863.             ;
  864.             state.isDrawn = 0
  865.  
  866.             ;  Handle trackball update. Rotate the top models
  867.             ;  oModelArray(0) and oModelArray(1)
  868.             ;
  869.             bHaveTransform = state.oTrack->Update(sEvent, TRANSforM=qmat )
  870.             if (bHaveTransform NE 0) then begin
  871.                 state.oModelArray(0)->GetProperty, TRANSforM=t
  872.                 mt = t # qmat
  873.                 state.oModelArray(0)->SetProperty, TRANSforM=mt
  874.                 state.oModelArray(1)->SetProperty, TRANSforM=mt
  875.             endif
  876.  
  877.             ;  Handle the button press event.
  878.             ;
  879.             if (sEvent.type EQ 0) then begin
  880.                 if ((sEvent.press EQ 1) AND (state.LMBscale EQ 1)) $
  881.                     then sEvent.press = 2
  882.                 if (sEvent.press EQ 2) then begin
  883.  
  884.                     ;  Scale the objects.
  885.                     ;
  886.                     xy = ([sEvent.x, sEvent.y] - state.center)
  887.                     r= TOTAL(xy^2) ; distance from center of unit circle
  888.                     state.sc(1) = SQRT(r)
  889.                     state.sc(2) = 1.0
  890.                 end else if (sEvent.press EQ 4) then begin ; right mouse button
  891.  
  892.                     ;  Pick a voxel point.
  893.                     ;
  894.                     j = state.oVolumeArray(state.cur)->pickvoxel(state.oWindow, $
  895.                         state.oView,[sEvent.x, sEvent.y])
  896.                     k = -1
  897.  
  898.                     if (j(0) NE -1) then begin
  899.                         state.oVolumeArray(state.cur)->GetProperty, $
  900.                             DATA0=dd, /NO_COPY
  901.                         k = dd(j(0),j(1),j(2))
  902.                         state.oVolumeArray(state.cur)->SetProperty, $
  903.                             DATA0=dd, /NO_COPY
  904.                     endif
  905.                     state.btndown = 4
  906.  
  907.                     ;  Display the point coordinates and its value.
  908.                     ;
  909.                     str = string(j(0),j(1),j(2),k, $
  910.                         FORMAT='("X=",I3.3,",Y=",I3.3,",Z=",I3.3,",Value=",I3.3)')
  911.  
  912.                     state.sText.text[6] = str
  913.                     textChange = ['coord']
  914.                     putTips, state.sText, state.wText[1], $
  915.                         textChange, [2]
  916.  
  917.                 endif
  918.  
  919.                 state.btndown = sEvent.press
  920.                 if (sEvent.press NE 4) then begin
  921.                     state.oWindow->SetProperty, QUALITY=0
  922.                 endif
  923.  
  924.                 WIDGET_CONTROL,state.wDraw, /DRAW_MOTION
  925.             endif
  926.  
  927.             ;  Handle the button motion.
  928.             ;
  929.             if ((sEvent.type eq 2) and $
  930.                 (state.btndown eq 4)) then begin
  931.  
  932.                 j = state.oVolumeArray(state.cur)->pickvoxel(state.oWindow, $
  933.                     state.oView,[sEvent.x,sEvent.y])
  934.                 k= -1
  935.                 if (j(0) NE -1) then begin
  936.                     state.oVolumeArray(state.cur)->GetProperty, DATA0=dd, /NO_COPY
  937.                     k = dd(j(0), j(1), j(2))
  938.                     state.oVolumeArray(state.cur)->SetProperty, DATA0=dd, /NO_COPY
  939.                 endif
  940.  
  941.                 ;  Display the voxel location and value.
  942.                 ;
  943.                 str = string(j(0),j(1),j(2),k, $
  944.                     FORMAT='("X=",I3.3,",Y=",I3.3,",Z=",I3.3,",Value=",I3.3)')
  945.                 state.sText.text[6] = str
  946.                 textChange = ['coord']
  947.                 putTips, state.sText, state.wText[1], $
  948.                     textChange, [2]
  949.  
  950.             endif else if ((sEvent.type eq 2) and $
  951.                 (state.btndown eq 2)) then begin
  952.  
  953.                 xy = ([sEvent.x,sEvent.y] - state.center) 
  954.                 r = total(xy^2) ; distance from center of unit circle
  955.                 state.sc(2) = (SQRT(r)/state.sc(1))/state.sc(2)
  956.                 state.oModelArray(1)->Scale, state.sc(2), state.sc(2), state.sc(2)
  957.                 state.oModelArray(0)->Scale, state.sc(2), state.sc(2), state.sc(2)
  958.                 state.sc(2) = (SQRT(r)/state.sc(1))
  959.                 state.oWindow->Draw, state.oView
  960.  
  961.             endif else if ((sEvent.type EQ 2) and $
  962.                 (state.btndown EQ 1)) then begin
  963.  
  964.                 if (bHaveTransform) then  begin
  965.                     state.oWindow->Draw, state.oView
  966.                 endif
  967.  
  968.             endif
  969.  
  970.             ;  Handle the button release.
  971.             ;
  972.             if (sEvent.type eq 1) then begin
  973.                 if (state.btndown EQ 1) then begin
  974.                     ;  do nothing for left mouse button.
  975.                 endif else if (state.btndown EQ 2) then begin
  976.                     state.sc(0) = state.sc(2)*state.sc(0)
  977.                 endif else if (state.btndown EQ 4) then begin
  978.                     j = state.oVolumeArray(state.cur)->pickvoxel(state.oWindow, $
  979.                         state.oView,[sEvent.x,sEvent.y])
  980.                 k = -1
  981.                 if (j(0) NE -1) then begin
  982.                         state.oVolumeArray(state.cur)->GetProperty, $
  983.                             DATA0=dd, /NO_COPY
  984.                         k = dd(j(0),j(1),j(2))
  985.                         state.oVolumeArray(state.cur)->SetProperty, $
  986.                             DATA0=dd, /NO_COPY
  987.  
  988.                         ;  Get the volume coord form.
  989.                         ;
  990.                 state.oVolumeArray(state.cur)->GetProperty, $
  991.                             XCOORD_CONV=x_conv, $
  992.                             YCOORD_CONV=y_conv, ZCOORD_CONV=z_conv
  993.  
  994.                         ;  Convert to normal coordinates.
  995.                         ;
  996.                 jack = FLTARR(3)
  997.                 jack(0) = x_conv(1)*j(0) + x_conv(0)
  998.                 jack(1) = y_conv(1)*j(1) + y_conv(0)
  999.                 jack(2) = z_conv(1)*j(2) + z_conv(0)
  1000.  
  1001.                         ;  If the bessel obj, apply the bessel zoom.
  1002.                         ;
  1003.                 if (state.cur EQ 2) then jack = jack*4.5
  1004.  
  1005.                         ;  Apply the difference.
  1006.                         ;
  1007.                 state.oOtherObjectArray(6)->Translate, $
  1008.                             jack(0)-state.jpos(0), $
  1009.                             jack(1)-state.jpos(1), jack(2)-state.jpos(2)
  1010.  
  1011.                         ;  Store the new location.
  1012.                         ;
  1013.                     state.jpos = jack
  1014.                     endif
  1015.  
  1016.                     ;  Display the voxel location and value.
  1017.                     ;
  1018.                     str = string(j(0),j(1),j(2),k, $
  1019.                         FORMAT='("X=",I3.3,",Y=",I3.3,",Z=",I3.3,",Value=",I3.3)')
  1020.                     state.sText.text[6] = str
  1021.                     textChange = ['coord']
  1022.                     putTips, state.sText, state.wText[1], $
  1023.                         textChange, [2]
  1024.  
  1025.                 endif
  1026.  
  1027.                 if (state.autoR EQ 1) then begin
  1028.                     state.oWindow->SetProperty, QUALITY=2
  1029.                 endif
  1030.  
  1031.                 if ((state.btndown NE 4) OR (state.autoR EQ 1)) then begin
  1032.  
  1033.                     if (state.autoR EQ 1) then begin
  1034.                         state.oWindow->SetProperty, QUALITY=2
  1035.                     endif else begin
  1036.                         state.oWindow->SetProperty, QUALITY=0
  1037.                     endelse
  1038.  
  1039.                     WIDGET_CONTROL, state.wBase, SENSITIVE=0
  1040.                     state.oWindow->Draw, state.oView
  1041.                     WIDGET_CONTROL, state.wBase, SENSITIVE=1
  1042.                 endif
  1043.                 state.btndown = 0
  1044.                 WIDGET_CONTROL, state.wDraw, DRAW_MOTION=0
  1045.  
  1046.             endif     ;  of event.type = 1
  1047.  
  1048.            WIDGET_CONTROL, sEvent.top, SET_UVALUE=state, /NO_COPY
  1049.  
  1050.         end   ;   of DRAW
  1051.  
  1052.         ;  Quit this application.
  1053.         ;
  1054.         'QUIT' : begin
  1055.             WIDGET_CONTROL, sEvent.top, /DESTROY
  1056.         end   ; of QUIT
  1057.  
  1058.         'ABOUT' : begin
  1059.             WIDGET_CONTROL, sEvent.top, GET_UVALUE=state, /NO_COPY
  1060.             state.isdrawn = 0
  1061.  
  1062.             ;  Verify that there is only one instance.
  1063.             ;
  1064.             if (Xregistered('XDisplayFile') EQ 0) then begin
  1065.                 XDisplayFile, filepath("volrendr.txt", $
  1066.                     SUBDIR=['examples','demo','demotext']), $
  1067.                     DONE_BUTTON='Done', $
  1068.                     TITLE="Volume", $
  1069.                     GROUP=sEvent.top, WIDTH=55, HEIGHT=14
  1070.             endif
  1071.             WIDGET_CONTROL, sEvent.top, SET_UVALUE=state, /NO_COPY
  1072.         end   ; of ABOUT
  1073.  
  1074.     endcase
  1075. end
  1076.  
  1077. ;----------------------------------------------------------------------------
  1078. ;
  1079. ;  Purpose:  Destroy the top objects and restore the previous
  1080. ;            color table.
  1081. ;
  1082. pro volrendr_Cleanup, $
  1083.     wTopBase        ;  IN: top level base identifier
  1084.  
  1085.     WIDGET_CONTROL, wTopBase, GET_UVALUE=state, /NO_COPY
  1086.  
  1087.     ;  Destroy the top objects.
  1088.     ;
  1089.     OBJ_DESTROY, state.oView
  1090.     OBJ_DESTROY, state.oTrack
  1091.     OBJ_DESTROY, state.oText
  1092.     OBJ_DESTROY, state.oFont
  1093.     OBJ_DESTROY, state.Font24
  1094.     OBJ_DESTROY, state.oContainer
  1095.  
  1096.     ;  Restore the color table.
  1097.     ;
  1098.     TVLCT, state.colorTable
  1099.  
  1100.     if widget_info(state.groupBase, /valid) then $
  1101.         widget_control, state.groupBase, /map
  1102.  
  1103. end   ;  of orbit_Cleanup
  1104.  
  1105.  
  1106.  
  1107. ;----------------------------------------------------------------------------
  1108. ;
  1109. ;  Purpose:  Perform volume rendering.
  1110. ;
  1111. pro d_volrendr, $
  1112.     GROUP=group, $     ; IN: (opt) group identifier
  1113.     APPTLB = appTLB    ; OUT: (opt) TLB of this application
  1114.  
  1115.     ; Check the validity of the group identifier
  1116.     ;
  1117.     ngroup = N_ELEMENTS(group)
  1118.     if (ngroup NE 0) then begin
  1119.         check = WIDGET_INFO(group, /VALID_ID)
  1120.         if (check NE 1) then begin
  1121.             print,'Error, the group identifier is not valid'
  1122.             print, 'Return to the main application'
  1123.             RETURN
  1124.         endif
  1125.         groupBase = group
  1126.     endif else groupBase = 0L
  1127.  
  1128.  
  1129.     ;  Get the current color vectors to restore
  1130.     ;  when this application is exited.
  1131.     ;
  1132.     TVLCT, savedR, savedG, savedB, /GET
  1133.  
  1134.     ; Build color table from color vectors
  1135.     ;
  1136.     colorTable = [[savedR],[savedG],[savedB]]
  1137.  
  1138.     ;  Set up dimensions of the drawing (viewing) area.
  1139.     ;
  1140.     device, GET_SCREEN_SIZE=scr
  1141.     xdim = scr(0)*0.6 *0.75
  1142.     ydim = xdim*0.8 *0.75
  1143.  
  1144.     ;  Get the tips.
  1145.     ;
  1146.     sText = getTips(filepath('volrendr.tip', $
  1147.         SUBDIR=['examples','demo', 'demotext']) )
  1148.  
  1149.     ;  Create widgets.
  1150.     ;
  1151.     if (N_ELEMENTS(group) EQ 0) then begin
  1152.         wBase = WIDGET_BASE(/COLUMN, XPAD=0, YPAD=0, $
  1153.             TITLE="Volumes", $
  1154.             /TLB_KILL_REQUEST_EVENTS, $
  1155.             TLB_FRAME_ATTR=1, MBAR=barBase)
  1156.     endif else begin
  1157.         wBase = WIDGET_BASE(/column, XPAD=0, YPAD=0, $
  1158.             TITLE="Volumes", $ 
  1159.             GROUP_LEADER=group, $
  1160.             /TLB_KILL_REQUEST_EVENTS, $
  1161.             TLB_FRAME_ATTR=1, MBAR=barBase)
  1162.     endelse
  1163.  
  1164.     ;  Create the menu bar. It contains the file|quit,
  1165.     ;  edit|shade-style, help|about buttons.
  1166.     ;
  1167.     fileMenu = WIDGET_BUTTON(barBase, VALUE='File', /MENU)
  1168.  
  1169.         wQuitButton = WIDGET_BUTTON(fileMenu, VALUE='Quit', UVALUE='QUIT')
  1170.  
  1171.  
  1172.     ;  Create the menu bar item Edit that has
  1173.     ;  the shade and style options.
  1174.     ;
  1175.     wOptionButton = WIDGET_BUTTON(barBase, VALUE='Options', /MENU)
  1176.  
  1177.         wLightButton = WIDGET_BUTTON(wOptionButton, $
  1178.             VALUE="Gradient Shading (off)", UVALUE='LIGHTING')
  1179.  
  1180.         ;  Provide the user the depth queueing code. Not implemented here.
  1181.         ;
  1182. ;        tDepth = WIDGET_BUTTON(wOptionButton, $
  1183. ;            VALUE="Depth Queuing (off)", UVALUE='DEPTHQ')
  1184.  
  1185.         ;  Offer the MIP rendering option.
  1186.         ;
  1187.         wSMIPButton = WIDGET_BUTTON(wOptionButton, $
  1188.             VALUE="MIP Rendering (off)", UVALUE='SMIP')
  1189.  
  1190.         ;  Set on or off the aut rendering option.
  1191.         ;
  1192.         wAutoRenderButton = WIDGET_BUTTON(wOptionButton, $
  1193.             VALUE="Auto-Render (off)", UVALUE='AUTORENDER')
  1194.  
  1195.         ;  Set the Left Mouse Button for scaling.
  1196.         ;
  1197.         wLmbButton = WIDGET_BUTTON(wOptionButton, $
  1198.             VALUE="Left mouse scale (off)", UVALUE='LMBSCALE')
  1199.  
  1200.         ;  Add the Color tables list
  1201.         ;  the options are contain in the file that end by   .pal
  1202.         ;
  1203.         wPaletteButton = WIDGET_BUTTON(wOptionButton, $
  1204.             MENU=1, VALUE="Color palette tables", /SEPARATOR)
  1205.  
  1206.             Add_Tables, '*.pal', wPaletteButton, $
  1207.                 'COLOR_TAB', colorList, colorWidgetID
  1208.  
  1209.         ; Add the opacity options
  1210.         ; The filenames must  end by    .opa
  1211.         ;
  1212.         wOpacityButton = WIDGET_BUTTON(wOptionButton, $
  1213.             MENU=1,VALUE="Opacity Tables")
  1214.  
  1215.             Add_Tables, '*.opa', wOpacityButton, $
  1216.                 'OPACITY_TAB', opacityList, opacityWidgetID
  1217.  
  1218.         ;  Add or remove a wire box object.
  1219.         ;
  1220.         wWireBoxButton = WIDGET_BUTTON(wOptionButton, $
  1221.             VALUE="Wire Box (off)", UVALUE='WIREBOX', /SEPARATOR)
  1222.  
  1223.         ;  Add or remove a solid plane object.
  1224.         ;
  1225.         wSolidPlaneButton = WIDGET_BUTTON(wOptionButton, $
  1226.             VALUE="Solid Plane (off)", UVALUE='SOLIDPLANE')
  1227.  
  1228.         ;  Add or remove axes object.
  1229.         ;
  1230.         wAxesButton = WIDGET_BUTTON(wOptionButton, $
  1231.             VALUE="Axes (off)", UVALUE='AXES')
  1232.  
  1233.         ;  Create the rendering steps options.
  1234.         ;
  1235.         wRenderStepButton = WIDGET_BUTTON(wOptionButton, $
  1236.             MENU=1, VALUE="Render step")
  1237.  
  1238.             wRenderStep111Button = WIDGET_BUTTON(wRenderStepButton, $
  1239.                 VALUE="Step 111", UVALUE='RENDERSTEP111')
  1240.  
  1241.             wRenderStep112Button = WIDGET_BUTTON(wRenderStepButton, $
  1242.                 VALUE="Step 112", UVALUE='RENDERSTEP112')
  1243.  
  1244.             wRenderStep114Button = WIDGET_BUTTON(wRenderStepButton, $
  1245.                 VALUE="Step 114", UVALUE='RENDERSTEP114')
  1246.  
  1247.             wRenderStep221Button = WIDGET_BUTTON(wRenderStepButton, $
  1248.                 VALUE="Step 221", UVALUE='RENDERSTEP221')
  1249.  
  1250.             wRenderStep222Button = WIDGET_BUTTON(wRenderStepButton, $
  1251.                 VALUE="Step 222", UVALUE='RENDERSTEP222')
  1252.  
  1253.             wRenderStep444Button = WIDGET_BUTTON(wRenderStepButton, $
  1254.                 VALUE="Step 444", UVALUE='RENDERSTEP444')
  1255.  
  1256.     ; Create the menu bar item help that contains the about button
  1257.     ;
  1258.     wHelpButton = WIDGET_BUTTON(barBase, VALUE='About', /HELP, /MENU)
  1259.  
  1260.         wAboutButton = WIDGET_BUTTON(wHelpButton, $
  1261.             VALUE='About volumes', UVALUE='ABOUT')
  1262.  
  1263.         ;  Create a sub base of the top base (wBase)
  1264.         ;
  1265.         subBase = WIDGET_BASE(wBase, COLUMN=2)
  1266.  
  1267.  
  1268.             ;  Create the left Base that contains the functionality buttons
  1269.             ;  Notably the object list and the option list
  1270.             ;
  1271.             wLeftbase = WIDGET_BASE(subBase, /COLUMN)
  1272.  
  1273.                 wVolBGroup = CW_BGROUP(wLeftBase, /COLUMN, $
  1274.                     ['Brain','Bessel'], $
  1275.                     /EXCLUSIVE, /NO_REL, /FRAME, UVALUE='VOLSEL', SET_VALUE=0)
  1276.  
  1277.                 ;  Create the render render button.
  1278.                 ;
  1279.                 wRenderButton = WIDGET_BUTTON(wLeftBase, $
  1280.                     VALUE="Render", UVALUE='RENDER', /ALIGN_CENTER)
  1281.  
  1282.                 ;  Create the right Base that has the drawing area.
  1283.                 ;
  1284.                 wRightbase = WIDGET_BASE(subBase, Column = 1)
  1285.  
  1286.                 ;  Create the drawing area.
  1287.                 ;
  1288.                 wDraw = WIDGET_DRAW(wRightBase, $
  1289.                     GRAPHICS_LEVEL=2, $
  1290.                     XSIZE=xdim, YSIZE=ydim, /BUTTON_EVENTS, UVALUE='DRAW', $
  1291.                     RETAIN=0, /EXPOSE_EVENTS)
  1292.  
  1293.         ;  Create the status line label.
  1294.         ;
  1295.         wStatusBase = WIDGET_BASE(wBase, MAP=0, /ROW)
  1296.  
  1297.             nWidgets = 2
  1298.             wText = LONARR(nWidgets)
  1299.             widTips, wStatusBase, sText.text, XSIZE=36, $
  1300.                 YSIZE=3, NWIDGETS=nWidgets, wText
  1301.  
  1302.     ;  Realize the base widget. 
  1303.     ;
  1304.     WIDGET_CONTROL, wBase, /REALIZE
  1305.  
  1306.     WIDGET_CONTROL, /HOURGLASS
  1307.  
  1308.     ; Returns the top level base to the APPTLB keyword.
  1309.     ;
  1310.     appTLB = wBase
  1311.  
  1312.     ;  Size the tips widgets.
  1313.     ;
  1314.     sizeTips, wBase, wText, wStatusBase
  1315.  
  1316.     WIDGET_CONTROL, wBase, /CLEAR_EVENTS
  1317.  
  1318.     WIDGET_CONTROL, wBase, SENSITIVE=0
  1319.  
  1320.     ;  Grab the window id of the drawable.
  1321.     ;
  1322.     WIDGET_CONTROL, wDraw, GET_VALUE=oWindow
  1323.  
  1324.     ;  Compute viewplane rect based on aspect ratio.
  1325.     ;
  1326.     aspect = FLOAT(xdim)/FLOAT(ydim)
  1327.     myview = [-1.0,-1.0,2,2]
  1328.  
  1329.     if (aspect > 1) then begin
  1330.         myview(0) = myview(0) - ((aspect-1.0)*myview(2))/2.0
  1331.         myview(2) = myview(2) * aspect
  1332.     endif else begin
  1333.         myview(1) = myview(1) - (((1.0/aspect)-1.0)*myview(3))/2.0
  1334.         myview(3) = myview(3) * aspect
  1335.     endelse
  1336.  
  1337.     ;  Create view.  
  1338.     ;
  1339.     oView = OBJ_NEW('idlgrview', PROJECTION=1, EYE=2.0, $
  1340.         ZCLIP=[1.0,-1.0], VIEWPLANE_RECT=myview,$
  1341.         COLOR=[0,0,0])
  1342.  
  1343.     ;  Create and display the PLEASE WAIT text.
  1344.     ;
  1345.     oFont = OBJ_NEW('IDLgrFont', 'Helvetica', SIZE=18)
  1346.     oText = OBJ_NEW('IDLgrText', $
  1347.         'Starting up  Please wait...', $
  1348.         ALIGN=0.5, $
  1349.         LOCATION=textLocation, $
  1350.         COLOR=[255,255,0], FONT=oFont)
  1351.  
  1352.  
  1353.     ; Create  model tree.
  1354.     ;
  1355.     oModelArray = OBJARR(4)
  1356.     oModelArray(3) = OBJ_NEW('IDLgrModel')
  1357.     oModelArray(0) = OBJ_NEW('IDLgrModel')
  1358.     oModelArray(3)->Add, oModelArray(0)
  1359.     oModelArray(1) = OBJ_NEW('IDLgrModel')
  1360.     oModelArray(3)->Add, oModelArray(1)
  1361.     oModelArray(2) = OBJ_NEW('IDLgrModel')
  1362.     oModelArray(3)->Add, oModelArray(2)
  1363.  
  1364.     ;  Add the top model to the view.
  1365.     ;
  1366.     oView->Add, oModelArray(3)
  1367.  
  1368.     oModelArray(3)->Add, oText
  1369.  
  1370.     ;  Draw the view.
  1371.     ;
  1372.     ;oWindow->Draw, oview
  1373.  
  1374.     ;  Load up the volumes.
  1375.     ;
  1376.     oVolumeArray = OBJARR(2)
  1377.     oVolumeArray(0) = load_volume('Brain',oModelArray(1))
  1378.     oVolumeArray(1) = load_volume('Bessel',oModelArray(1))
  1379.  
  1380.     ;  Rotate so the Brain looks good...
  1381.     ;
  1382.     oModelArray(1)->Rotate,[0,1,0],90
  1383.     oModelArray(0)->Rotate,[0,1,0],90
  1384.     oModelArray(1)->Rotate,[1,0,0],180
  1385.     oModelArray(0)->Rotate,[1,0,0],180
  1386.  
  1387.     ;  Create other intermixed objects.
  1388.     ;
  1389.     oOtherObjectArray = OBJARR(7)
  1390.  
  1391.     ;  Create a wire box.
  1392.     ;
  1393.     xp=[-0.25, 0.25, 0.25,-0.25, $
  1394.         -0.25, 0.25, 0.25,-0.25]
  1395.     yp=[-0.25,-0.25, 0.25, 0.25, $
  1396.         -0.25,-0.25, 0.25, 0.25]
  1397.     zp=[ 0.25, 0.25, 0.25, 0.25, $
  1398.         -0.25,-0.25,-0.25,-0.25]
  1399.     pl=[5,0,1,2,3,0, $
  1400.         5,4,5,6,7,4, $
  1401.         2,0,4, $
  1402.         2,1,5, $
  1403.         2,2,6, $
  1404.         2,3,7]
  1405.  
  1406.     oOtherObjectArray(0) = OBJ_NEW('IDLgrpolyline', xp, yp, zp, $
  1407.         POLYLINES=pl, COLOR=[255,255,255])
  1408.  
  1409.     oModelArray(0)->Add, oOtherObjectArray(0)
  1410.  
  1411.     ;  Create a solid plane.
  1412.     ;
  1413.     o = 0.3
  1414.     verts = TRANSPOSE([[-o,o,o,-o],[-o,-o,o,o],[-o,-o,o,o]])
  1415.     poly = [4,0,1,2,3]
  1416.     vc = [[0B,255B,0B],[0B,0B,255B],[255B,255B,255B],[255B,0B,0B]]
  1417.  
  1418.     oOtherObjectArray(1) = OBJ_NEW('IDLgrPolygon', verts, POLYGONS=poly, $
  1419.         VERT_COLOR=vc, SHADING=1)
  1420.  
  1421.     oModelArray(0)->Add, oOtherObjectArray(1)
  1422.  
  1423.     ;  Create axes
  1424.     ;
  1425.     xpc = [-1.,1.,0.,0.,0.,0.]
  1426.     ypc = [0.,0.,-1.,1.,0.,0.]
  1427.     zpc = [0.,0.,0.,0.,-1.,1.]
  1428.     plc = [2,0,1,2,2,3,2,4,5]
  1429.     vcc = [[255B,0B,0B],[255B,0B,0B], $
  1430.            [0B,255B,0B],[0B,255B,0B], $
  1431.            [0B,0B,255B],[0B,0B,255B] $
  1432.           ]
  1433.  
  1434.     oOtherObjectArray(2) = OBJ_NEW('IDLgrpolyline', xpc, ypc, zpc, $
  1435.         POLYLINES=plc, VERT_COLOR=vcc)
  1436.  
  1437.     ;  Something to move the axes with.
  1438.     ;
  1439.     oOtherObjectArray(6) = OBJ_NEW('idlgrmodel')
  1440.     oOtherObjectArray(6)->Add,  oOtherObjectArray(2)
  1441.     oModelArray(0)->Add,  oOtherObjectArray(6)
  1442.  
  1443.  
  1444.     ;  Create a text for information on the objects.
  1445.     ;
  1446.     font24 = OBJ_NEW( 'IDLgrFont', 'Helvetica', size=18. )
  1447.     oOtherObjectArray(3) = OBJ_NEW( 'IDLgrText', LOCATION=[10,10], $
  1448.         'Hog heart, 132x202x144, X-ray CT', COLOR=[255,255,0], $
  1449.         FONT=font24)
  1450.  
  1451.     oModelArray(2)->Add, oOtherObjectArray(3)
  1452.     oOtherObjectArray(4) = OBJ_NEW( 'IDLgrText', LOCATION=[10,10], $
  1453.         'Human brain, 256x256x124, MRI (T2)', COLOR=[255,255,0], $
  1454.         FONT=font24,HIDE=1)
  1455.  
  1456.     oModelArray(2)->Add, oOtherObjectArray(4)
  1457.     oOtherObjectArray(5) = OBJ_NEW( 'IDLgrText', LOCATION=[10,10], $
  1458.         'Swept Bessel series, 40x40x20', COLOR=[255,255,0], $
  1459.         FONT=font24,HIDE=1)
  1460.  
  1461.     oModelArray(2)->Add, oOtherObjectArray(5)
  1462.  
  1463.     ;  Set  to thick lines.
  1464.     ;
  1465.     if (N_elements(thick) NE 0) then begin
  1466.         oOtherObjectArray(2)->SetProperty, THICK=2.0
  1467.         oOtherObjectArray(0)->SetProperty, THICK=2.0
  1468.     end
  1469.  
  1470.     ;  Hide the volume objects to start.
  1471.     ;
  1472.     oOtherObjectArray(0)->SetProperty,HIDE=1
  1473.     oOtherObjectArray(1)->SetProperty,HIDE=1
  1474.     oOtherObjectArray(2)->SetProperty,HIDE=1
  1475.  
  1476.     ;  Create s lights.
  1477.     ;
  1478.     vl = OBJ_NEW('IDLgrLight', DIRECTION=[-1,0,1], TYPE=2)
  1479.     vl->SetProperty, COLOR=[255,255,255], INTENSITY=1.0
  1480.     oModelArray(3)->Add, vl
  1481.  
  1482.     sl = OBJ_NEW('IDLgrLight', TYPE=0, INTENSITY=1.0)
  1483.     oModelArray(3)->Add, sl
  1484.  
  1485.  
  1486.     ;  Enable the brain volume.
  1487.     ;
  1488.     oVolumeArray(0)->SetProperty, HIDE=0
  1489.  
  1490.     ;  Set the axes) to not showing.
  1491.     ;
  1492.     jack = FLTARR(3)
  1493.     jack = [0.0,0.0,0.0]
  1494.  
  1495.     ;  Add the trackball object for interactive change
  1496.     ;  of the scene orientation
  1497.     ;
  1498.     oTrack = OBJ_NEW('Trackball', [xdim/2.0, ydim/2.0], xdim/2.0)
  1499.  
  1500.     oContainer = OBJ_NEW('IDLgrContainer')
  1501.     oContainer->Add, oView
  1502.     oContainer->Add, oTrack
  1503.  
  1504.  
  1505.     ;  Initialize the isdrawn flag.
  1506.     ;  When isDrawn = 0, it indicates that the object has not
  1507.     ;  been drawn yet and the expose event will draw it. When
  1508.     ;  isDrawn = 1,  it indicates that the object has been drawn
  1509.     ;  and that the expose event will skip the drawing command.
  1510.     ;  
  1511.     isDrawn = 1
  1512.  
  1513.     ;  Save the state  structure.
  1514.     ;
  1515.     state = { $
  1516.         center: xdim/2., $          ; X Center of drawing area
  1517.         radius: ydim/2, $           ; Shpere radius (1/2 of draw area height)
  1518.         btndown: 0b, $              ; 0= mouse button down, other =not down
  1519.         pt0: FLTARR(3), $           ; Position point 0
  1520.         pt1: FLTARR(3), $           ; Position point 1
  1521.         sc : FLTARR(3), $           ; Scaling factor for x, y, z directions
  1522.         wDraw: wDraw, $             ; Widget draw ID
  1523.         oModelArray: oModelArray, $ ; Model array
  1524.         cur: 0, $                   ; Current object shown (0=brain, 1=bessel)
  1525.         OVolumeArray: $
  1526.             oVolumeArray, $         ; Volume object array
  1527.         oOtherObjectArray:  $
  1528.             oOtherObjectArray, $    ; Other objects array
  1529.         OView: oView, $             ; View object
  1530.         font24: font24, $            
  1531.         OWindow: oWindow, $         ; Window object
  1532.         WText: wText, $             ; Widget text IDs for tips
  1533.         SText: sText, $             ; Text structure for tips
  1534.         jpos : jack, $              ; Axes position
  1535.         autoR : 0, $                ; Autorender,  0: off,   1: on
  1536.         ColorTable: colorTable, $   ; Color table to restore
  1537.         Initial : 0, $              ; Initial state 
  1538.         OTrack: oTrack, $           ; Trackball object
  1539.         OText: oText, $             ; Text object
  1540.         OFont: oFont, $             ; Font object
  1541.         OContainer: oContainer, $   ; container object
  1542.         WBase : wBase, $            ; top level base
  1543.         WRenderStep111Button :  $   ; Render step button IDs
  1544.             wRenderStep111Button, $
  1545.         WRenderStep112Button :  $
  1546.             wRenderStep112Button, $
  1547.         WRenderStep114Button :  $
  1548.             wRenderStep114Button, $
  1549.         WRenderStep221Button : $
  1550.             wRenderStep221Button, $
  1551.         WRenderStep222Button : $
  1552.             wRenderStep222Button, $
  1553.         WRenderStep444Button : $
  1554.             wRenderStep444Button, $
  1555.         ColorWidgetID :  $
  1556.             ColorWidgetID, $        ; Color palette button IDs array
  1557.         OpacityWidgetID :  $
  1558.             opacityWidgetID, $      ; Opacity table button IDs array
  1559.         Isdrawn : isDrawn, $        ; 0 =object not drawn, 1 = object drawn
  1560.         RenderStepFlag : 0, $       ; Render step flag 0= not rendered, 1=is
  1561.         LMBscale : 0, $             ; Left mouse button scaling mode: 0=not on, 1=on
  1562.         groupBase: groupBase $      ; Base of Group Leader
  1563.     }  
  1564.  
  1565.  
  1566.     ;  Set the scaling factor.
  1567.     ;
  1568.     state.sc(0) = 1.0
  1569.  
  1570.     ;  Set the render step to [ 1, 1, 1,].
  1571.     ;
  1572.     step=[1,1,1]
  1573.     oVolumeArray(0)->SetProperty, RENDER_STEP=step
  1574.     oVolumeArray(1)->SetProperty, RENDER_STEP=step
  1575.     WIDGET_CONTROL, wRenderStep111Button, SENSITIVE=0
  1576.  
  1577.  
  1578.     WIDGET_CONTROL, /hourglass    
  1579.     oWindow->SetProperty, QUALITY=2
  1580.  
  1581.     ;  Draw the view.
  1582.     ;
  1583.     Set_Table, state.oVolumeArray(0), colorWidgetID(1), 0
  1584.     Set_Table, state.oVolumeArray(0), opacityWidgetID(2), 1
  1585.  
  1586.     ;  Desensitize the default color and opacity 
  1587.     ;  ( solid in both cases)
  1588.     ;
  1589.     WIDGET_CONTROL, colorWidgetID(1), SENSITIVE=0 
  1590.     WIDGET_CONTROL, opacityWidgetID(2), SENSITIVE=0 
  1591.  
  1592.     WIDGET_CONTROL, wBase, SET_UVALUE=state, /NO_COPY
  1593.  
  1594.     WIDGET_CONTROL, wBase, SENSITIVE=1
  1595.  
  1596.     oModelArray(3)->Remove, oText
  1597.  
  1598.     oWindow->Draw, oView    
  1599.  
  1600.     XMANAGER, 'd_volrendr', wBase, Event_Handler='volrendr_event', $
  1601.         CLEANUP='volrendr_Cleanup'
  1602.  
  1603. end   ;  of d_volrendr.pro
  1604.